﻿// (c) Copyright 2013 Mike Riedel.
// This source is subject to the Microsoft Public License (Ms-PL).
// All other rights reserved.

using System.Diagnostics;
using FreshMeat.MiniHsm;

namespace FreshMeat.MiniHsmTest
{
   /// <summary>
   /// Root has substate S (default)
   /// S has substates S1 (default) and S2
   /// S1 has substates S11 (default) and S12
   /// S2 has substates S21 (default) and S22
   /// </summary>
   [DebuggerDisplay("CurrentState={CurrentState}")]
   internal class MockMachine : MiniMachine<MockMachine.Input>
   {
      bool enableTracking;
      public int Step;

      public Tracker EnterS;
      public Tracker ExitS;
      public Tracker DefaultS;
      public Tracker EnterS1;
      public Tracker ExitS1;
      public Tracker DefaultS1;
      public Tracker EnterS11;
      public Tracker ExitS11;
      public Tracker EnterS12;
      public Tracker ExitS12;
      public Tracker EnterS2;
      public Tracker ExitS2;
      public Tracker DefaultS2;
      public Tracker EnterS21;
      public Tracker ExitS21;
      public Tracker EnterS22;
      public Tracker ExitS22;

      public enum Input
      {
         GetParent = -4,
         SetDefault,
         Enter,
         Exit,
         GoToS1,
         GoToS11,
         GoToS12,
         GoToS2,
         GoToS21,
         GoToS22
      }

      public MockMachine(bool enableTracking)
         : base(Input.GetParent, Input.SetDefault, Input.Enter, Input.Exit)
      {
         this.enableTracking = enableTracking;
         DefaultTo(S);
      }

      public string CurrentState
      {
         get { return GetCurrentState(); }
      }

      State S(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Step = EnterS.Update(enableTracking, Step);
               return null;

            case Input.SetDefault:
               Step = DefaultS.Update(enableTracking, Step);
               DefaultTo(S1);
               return null;

            case Input.Exit:
               Step = ExitS.Update(enableTracking, Step);
               return null;

            case Input.GoToS1:
               TransitionTo(S1);
               return null;

            case Input.GoToS11:
               TransitionTo(S11);
               return null;

            case Input.GoToS12:
               TransitionTo(S12);
               return null;

            case Input.GoToS2:
               TransitionTo(S2);
               return null;

            case Input.GoToS21:
               TransitionTo(S21);
               return null;

            case Input.GoToS22:
               TransitionTo(S22);
               return null;
         }

         return Root;
      }

      State S1(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Step = EnterS1.Update(enableTracking, Step);
               return null;

            case Input.SetDefault:
               Step = DefaultS1.Update(enableTracking, Step);
               DefaultTo(S11);
               return null;

            case Input.Exit:
               Step = ExitS1.Update(enableTracking, Step);
               return null;
         }

         return S;
      }

      State S11(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Step = EnterS11.Update(enableTracking, Step);
               return null;

            case Input.Exit:
               Step = ExitS11.Update(enableTracking, Step);
               return null;
         }

         return S1;
      }

      State S12(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Step = EnterS12.Update(enableTracking, Step);
               return null;

            case Input.Exit:
               Step = ExitS12.Update(enableTracking, Step);
               return null;
         }

         return S1;
      }

      State S2(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Step = EnterS2.Update(enableTracking, Step);
               return null;

            case Input.SetDefault:
               Step = DefaultS2.Update(enableTracking, Step);
               DefaultTo(S21);
               return null;

            case Input.Exit:
               Step = ExitS2.Update(enableTracking, Step);
               return null;
         }

         return S;
      }

      State S21(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Step = EnterS21.Update(enableTracking, Step);
               return null;

            case Input.Exit:
               Step = ExitS21.Update(enableTracking, Step);
               return null;
         }

         return S2;
      }

      State S22(Input input)
      {
         switch (input)
         {
            case Input.Enter:
               Step = EnterS22.Update(enableTracking, Step);
               return null;

            case Input.Exit:
               Step = ExitS22.Update(enableTracking, Step);
               return null;
         }

         return S2;
      }

      public void Update(Input input, bool enableTrackingNow)
      {
         if (enableTrackingNow)
            enableTracking = true;

         Process(input);
      }
   }

   [DebuggerDisplay("Step={Step}, Count={Count}")]
   internal struct Tracker
   {
      public int Step;
      public int Count;

      public int Update(bool enable, int step)
      {
         if (enable)
         {
            Step = ++step;
            Count++;
         }

         return step;
      }
   }
}
